package wangwenjun.phase2.concurrencypattern.activeobject.dynamicproxy.framework;

import lombok.extern.slf4j.Slf4j;
import wangwenjun.phase2.concurrencypattern.future.FutureImpl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author ChangLiang
 * @date 2020/6/18
 */
@Slf4j
class ActiveObjectMessage {

    /**
     * 接口方法的参数
     */
    private final Object[] params;

    /**
     * 接口方法
     */
    private final Method method;

    /**
     * 有返回值的方法，会返回
     */
    private final FutureImpl<Object> future;

    /**
     * 具体的Service 接口
     */
    private final Object service;

    public ActiveObjectMessage(Builder builder) {
        this.params = builder.params;
        this.method = builder.method;
        this.future = builder.future;
        this.service = builder.service;
    }

    public void execute() {
        try {
            // 这个地方开始调用OrderServiceImpl#service的method方法
//            log.info("ActiveObjectMessage  service:{}, method:{}", service.getClass().toString(), method.getProductName());
            Object result = method.invoke(service, params);
            if (future != null) {
                FutureImpl<Object> futureServiceFutureImpl = (FutureImpl<Object>) result;
                log.info("FutureService#FutureImpl:{}", futureServiceFutureImpl.toString());
                // 如果是有返回值的接口方法， 则需要通过get 方法获得最终的结果
                Object realResult = futureServiceFutureImpl.get();
                future.finish(realResult);
            }
        } catch (IllegalAccessException | InvocationTargetException | InterruptedException e) {
            /**
             * 如果发生异常， 那么有返回值的方法将会显式地指定结果为null ， 无返回值的接口方法则
             * 会忽略该异常
             */
            if (future != null) {
                future.finish(null);
            }
        }
    }

    static class Builder{
        private Object[] params;

        private Method method;

        private FutureImpl<Object> future;

        private Object service;

        public Builder method(Method method) {
            this.method = method;
            return this;
        }

        public Builder future(FutureImpl<Object> future) {
            this.future = future;
            return this;
        }

        public Builder params(Object[] params) {
            this.params = params;
            return this;
        }

        public Builder service(Object service) {
            this.service = service;
            return this;
        }

        public ActiveObjectMessage build() {
            return new ActiveObjectMessage(this);
        }
    }
}
